#include "kservice/display.h"
#include "kernel/astralapi.h"

static int shift_row(Display d, int num)
{

    for (int y = d->tstart; y < d->thight - num; y++)
    {
        int off = y * d->twidth;
        int tar = (y + num) * d->twidth;
        for (int x = 0; x < d->twidth; x++)
        {
            d->buff[off + x] = d->buff[tar + x];
        }
    }

    for (int y = d->thight - num; y < d->thight; y++)
    {
        int off = y * d->twidth;
        for (int x = 0; x < d->twidth; x++)
        {
            d->buff[off + x] = 0x00ffffff;
        }
    }
    d->tcurry -= num;
    return num;
}

void create_display(Display d, char *name, unsigned *buff, int byte_size)
{
    for (int i = 0; i < byte_size; i++)
    {
        *(buff + i) = 0x00ffffff;
    }
    d->buff = buff;
    d->byte_size = byte_size;
}

void set_display_attr(Display d, int width, int heigt, int reserve_lines)
{
    d->tcurrx = 0;
    d->tcurry = reserve_lines;
    d->twidth = width;
    d->thight = heigt;
    d->tstart = reserve_lines;
}

int switch_display(Display d)
{

    AstralDevice mon = open_device("mon1");
    if (mon)
    {
        mon->operations->dopen(mon, NULL);
        mon->status = OPENED;
        mon->operations->dwrite(mon, CAST_AS(char*, d->buff), 0, 0);
        d->status = CONNECTED;
    }
    return d->status;
}

static int is_showable(char c)
{
    return (31 < c) && (c < 127);
}


void display_char(Display d, char c, unsigned color_fg, unsigned color_bg)
{
    if (c == '\n')
    {
        d->tcurrx = 0;
        d->tcurry += 16;
        return;
    }
    if (c == '\r')
    {
        d->tcurrx = 0;
        return;
    }
    if (!is_showable(c))
    {
        return;
    }

    d->tcurrx += 8;
    if (d->tcurrx >= d->twidth)
    {
        d->tcurrx = 0;
        d->tcurry += 16;
    }

    if (d->tcurry >= d->thight - 16)
    {
        shift_row(d, 16);
    }

    unsigned offset = (unsigned char)c * 16;
    const unsigned char *ca = get_front() + offset;

    for (int r = 0; r < 16; r++)
    {
        int yy = d->tcurry + r;
        unsigned char byte = *(ca + r);
        for (int bit = 0; bit < 8; bit++)
        {
            int xx = d->tcurrx + bit;
            if (byte & (1 << bit))
            {
                d->buff[xx + yy * d->twidth] = color_fg;
            }
            else
            {
                d->buff[xx + yy * d->twidth] = color_bg;
            }
        }
    }
}
